home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / vid_sunx.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  30KB  |  1,258 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // vid_x.c -- general x video driver
  21.  
  22. #define _BSD
  23.  
  24. #include <sys/time.h>
  25. #include <sys/types.h>
  26. #include <unistd.h>
  27. #include <signal.h>
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <sys/ipc.h>
  32. #include <sys/shm.h>
  33. #include <X11/Xlib.h>
  34. #include <X11/Xutil.h>
  35. #include <X11/Xatom.h>
  36. #include <X11/keysym.h>
  37. #include <X11/extensions/XShm.h>
  38.  
  39. #include "quakedef.h"
  40. #include "d_local.h"
  41.  
  42. cvar_t        m_filter = {"m_filter","0", true};
  43.  
  44. qboolean        mouse_avail;
  45. int             mouse_buttons=3;
  46. int             mouse_oldbuttonstate;
  47. int             mouse_buttonstate;
  48. float   mouse_x, mouse_y;
  49. float   old_mouse_x, old_mouse_y;
  50. int p_mouse_x;
  51. int p_mouse_y;
  52. qboolean    mouse_grabbed = false; // we grab it when console is up
  53.  
  54. int        VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar;
  55. byte    *VGA_pagebase;
  56.  
  57. // The following X property format is defined in Motif 1.1's
  58. // Xm/MwmUtils.h, but QUAKE should not depend on that header
  59. // file. Note: Motif 1.2 expanded this structure with
  60. // uninteresting fields (to QUAKE) so just stick with the
  61. // smaller Motif 1.1 structure.
  62.  
  63. #define MWM_HINTS_DECORATIONS   2
  64. typedef struct
  65. {
  66.     long flags;
  67.     long functions;
  68.     long decorations;
  69.     long input_mode;
  70. } MotifWmHints;
  71.  
  72. #define MAX_COLUMN_SIZE    11
  73.  
  74. #define MAX_MODEDESCS    (MAX_COLUMN_SIZE*3)
  75.  
  76. typedef struct
  77. {
  78.     int        modenum;
  79.     int        iscur;
  80.     char    desc[256];
  81. } modedesc_t;
  82.  
  83. extern void M_Menu_Options_f (void);
  84. extern void M_Print (int cx, int cy, char *str);
  85. extern void M_PrintWhite (int cx, int cy, char *str);
  86. extern void M_DrawCharacter (int cx, int line, int num);
  87. extern void M_DrawTransPic (int x, int y, qpic_t *pic);
  88. extern void M_DrawPic (int x, int y, qpic_t *pic);
  89.  
  90. extern int sb_updates;
  91. extern int x_root, y_root; // root window relative mouse coords
  92.  
  93. typedef struct
  94. {
  95.     int input;
  96.     int output;
  97. } keymap_t;
  98.  
  99. viddef_t vid; // global video state
  100. unsigned short       d_8to16table[256];
  101.  
  102. int        num_shades=32;
  103.  
  104. int    d_con_indirect = 0;
  105.  
  106. int        vid_buffersize;
  107.  
  108. #define STD_EVENT_MASK \
  109. ( KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \
  110. PointerMotionMask | EnterWindowMask | LeaveWindowMask | VisibilityChangeMask | \
  111. ExposureMask | StructureNotifyMask )
  112.  
  113. qboolean                x_fullscreen = true;
  114. Display                    *x_disp = NULL;
  115. int                        x_screen, x_screen_width, x_screen_height;
  116. int                x_center_width, x_center_height;
  117. int                        x_std_event_mask = STD_EVENT_MASK;
  118. Window                    x_win, x_root_win;
  119. qboolean                mouse_in_window = false;
  120. int                global_dx, global_dy;
  121.  
  122. static qboolean            doShm;
  123. static Colormap            x_cmap;
  124. static GC                x_gc;
  125. static Visual            *x_vis;
  126. static XVisualInfo        *x_visinfo;
  127. static Atom                aHints = 0;
  128. static Atom                aWMDelete = 0;
  129.  
  130. static int                x_shmeventtype;
  131. //static XShmSegmentInfo    x_shminfo;
  132.  
  133. static qboolean            oktodraw = false;
  134.  
  135. int XShmQueryExtension(Display *);
  136. int XShmGetEventBase(Display *);
  137.  
  138. int current_framebuffer;
  139. static XImage            *x_framebuffer[2] = { 0, 0 };
  140. static XShmSegmentInfo    x_shminfo[2];
  141.  
  142. static int verbose=1;
  143.  
  144. static byte current_palette[768];
  145.  
  146. typedef unsigned short PIXEL16;
  147. typedef unsigned long PIXEL24;
  148. static PIXEL16 st2d_8to16table[256];
  149. static PIXEL24 st2d_8to24table[256];
  150. static int shiftmask_fl=0;
  151. static long r_shift,g_shift,b_shift;
  152. static unsigned long r_mask,g_mask,b_mask;
  153.  
  154. void shiftmask_init()
  155. {
  156.     unsigned int x;
  157.     r_mask=x_vis->red_mask;
  158.     g_mask=x_vis->green_mask;
  159.     b_mask=x_vis->blue_mask;
  160.     for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;
  161.     for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;
  162.     for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;
  163.     shiftmask_fl=1;
  164. }
  165.  
  166. PIXEL16 xlib_rgb16(int r,int g,int b)
  167. {
  168.     PIXEL16 p;
  169.     if(shiftmask_fl==0) shiftmask_init();
  170.     p=0;
  171.  
  172.     if(r_shift>0) {
  173.         p=(r<<(r_shift))&r_mask;
  174.     } else if(r_shift<0) {
  175.         p=(r>>(-r_shift))&r_mask;
  176.     } else p|=(r&r_mask);
  177.  
  178.     if(g_shift>0) {
  179.         p|=(g<<(g_shift))&g_mask;
  180.     } else if(g_shift<0) {
  181.         p|=(g>>(-g_shift))&g_mask;
  182.     } else p|=(g&g_mask);
  183.  
  184.     if(b_shift>0) {
  185.         p|=(b<<(b_shift))&b_mask;
  186.     } else if(b_shift<0) {
  187.         p|=(b>>(-b_shift))&b_mask;
  188.     } else p|=(b&b_mask);
  189.  
  190.     return p;
  191. }
  192.  
  193. PIXEL24 xlib_rgb24(int r,int g,int b)
  194. {
  195.     PIXEL24 p;
  196.     if(shiftmask_fl==0) shiftmask_init();
  197.     p=0;
  198.  
  199.     if(r_shift>0) {
  200.         p=(r<<(r_shift))&r_mask;
  201.     } else if(r_shift<0) {
  202.         p=(r>>(-r_shift))&r_mask;
  203.     } else p|=(r&r_mask);
  204.  
  205.     if(g_shift>0) {
  206.         p|=(g<<(g_shift))&g_mask;
  207.     } else if(g_shift<0) {
  208.         p|=(g>>(-g_shift))&g_mask;
  209.     } else p|=(g&g_mask);
  210.  
  211.     if(b_shift>0) {
  212.         p|=(b<<(b_shift))&b_mask;
  213.     } else if(b_shift<0) {
  214.         p|=(b>>(-b_shift))&b_mask;
  215.     } else p|=(b&b_mask);
  216.  
  217.     return p;
  218. }
  219.  
  220. void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
  221. {
  222.     int xi,yi;
  223.     unsigned char *src;
  224.     PIXEL16 *dest;
  225.     register int count, n;
  226.  
  227.     if( (x<0)||(y<0) )return;
  228.  
  229.     for (yi = y; yi < (y+height); yi++) {
  230.         src = &framebuf->data [yi * framebuf->bytes_per_line];
  231.  
  232.         // Duff's Device
  233.         count = width;
  234.         n = (count + 7) / 8;
  235.         dest = ((PIXEL16 *)src) + x+width - 1;
  236.         src += x+width - 1;
  237.  
  238.         switch (count % 8) {
  239.         case 0:    do {    *dest-- = st2d_8to16table[*src--];
  240.         case 7:            *dest-- = st2d_8to16table[*src--];
  241.         case 6:            *dest-- = st2d_8to16table[*src--];
  242.         case 5:            *dest-- = st2d_8to16table[*src--];
  243.         case 4:            *dest-- = st2d_8to16table[*src--];
  244.         case 3:            *dest-- = st2d_8to16table[*src--];
  245.         case 2:            *dest-- = st2d_8to16table[*src--];
  246.         case 1:            *dest-- = st2d_8to16table[*src--];
  247.                 } while (--n > 0);
  248.         }
  249.  
  250. //        for(xi = (x+width-1); xi >= x; xi--) {
  251. //            dest[xi] = st2d_8to16table[src[xi]];
  252. //        }
  253.     }
  254. }
  255.  
  256. void st3_fixup( XImage *framebuf, int x, int y, int width, int height)
  257. {
  258.     int xi,yi;
  259.     unsigned char *src;
  260.     PIXEL24 *dest;
  261.     register int count, n;
  262.  
  263.     if( (x<0)||(y<0) )return;
  264.  
  265.     for (yi = y; yi < (y+height); yi++) {
  266.         src = &framebuf->data [yi * framebuf->bytes_per_line];
  267.  
  268.         // Duff's Device
  269.         count = width;
  270.         n = (count + 7) / 8;
  271.         dest = ((PIXEL24 *)src) + x+width - 1;
  272.         src += x+width - 1;
  273.  
  274.         switch (count % 8) {
  275.         case 0:    do {    *dest-- = st2d_8to24table[*src--];
  276.         case 7:            *dest-- = st2d_8to24table[*src--];
  277.         case 6:            *dest-- = st2d_8to24table[*src--];
  278.         case 5:            *dest-- = st2d_8to24table[*src--];
  279.         case 4:            *dest-- = st2d_8to24table[*src--];
  280.         case 3:            *dest-- = st2d_8to24table[*src--];
  281.         case 2:            *dest-- = st2d_8to24table[*src--];
  282.         case 1:            *dest-- = st2d_8to24table[*src--];
  283.                 } while (--n > 0);
  284.         }
  285.  
  286. //        for(xi = (x+width-1); xi >= x; xi--) {
  287. //            dest[xi] = st2d_8to16table[src[xi]];
  288. //        }
  289.     }
  290. }
  291.  
  292. /*
  293. ================
  294. D_BeginDirectRect
  295. ================
  296. */
  297. void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
  298. {
  299. // direct drawing of the "accessing disk" icon isn't supported under Nextstep
  300. }
  301.  
  302.  
  303. /*
  304. ================
  305. D_EndDirectRect
  306. ================
  307. */
  308. void D_EndDirectRect (int x, int y, int width, int height)
  309. {
  310. // direct drawing of the "accessing disk" icon isn't supported under Nextstep
  311. }
  312.  
  313.  
  314. /*
  315. =================
  316. VID_Gamma_f
  317.  
  318. Keybinding command
  319. =================
  320. */
  321.  
  322. byte vid_gamma[256];
  323.  
  324. void VID_Gamma_f (void)
  325. {
  326.  
  327.     float    g, f, inf;
  328.     int        i;
  329.  
  330.     if (Cmd_Argc () == 2)
  331.     {
  332.         g = Q_atof (Cmd_Argv(1));
  333.  
  334.         for (i=0 ; i<255 ; i++)
  335.         {
  336.             f = pow ((i+1)/256.0, g);
  337.             inf = f*255 + 0.5;
  338.             if (inf < 0)
  339.                 inf = 0;
  340.             if (inf > 255)
  341.                 inf = 255;
  342.             vid_gamma[i] = inf;
  343.         }
  344.  
  345.         VID_SetPalette (current_palette);
  346.  
  347.         vid.recalc_refdef = 1;                // force a surface cache flush
  348.     }
  349.  
  350. }
  351.  
  352. // ========================================================================
  353. // Tragic death handler
  354. // ========================================================================
  355.  
  356. void TragicDeath(int signal_num)
  357. {
  358.     //XAutoRepeatOn(x_disp);
  359.     VID_Shutdown();
  360.     Sys_Error("This death brought to you by the number %d\n", signal_num);
  361. }
  362.  
  363. // ========================================================================
  364. // makes a null cursor
  365. // ========================================================================
  366.  
  367. static Cursor CreateNullCursor(Display *display, Window root)
  368. {
  369.     Pixmap cursormask; 
  370.     XGCValues xgc;
  371.     GC gc;
  372.     XColor dummycolour;
  373.     Cursor cursor;
  374.  
  375.     cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
  376.     xgc.function = GXclear;
  377.     gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
  378.     XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
  379.     dummycolour.pixel = 0;
  380.     dummycolour.red = 0;
  381.     dummycolour.flags = 04;
  382.     cursor = XCreatePixmapCursor(display, cursormask, cursormask,
  383.           &dummycolour,&dummycolour, 0,0);
  384.     XFreePixmap(display,cursormask);
  385.     XFreeGC(display,gc);
  386.     return cursor;
  387. }
  388.  
  389. void ResetFrameBuffer(void)
  390. {
  391.  
  392.     int mem;
  393.     int pwidth;
  394.  
  395.     if (x_framebuffer[0])
  396.     {
  397.         Z_Free(x_framebuffer[0]->data);
  398. //        Z_Free(d_pzbuffer);
  399.         free(x_framebuffer[0]);
  400.     }
  401.  
  402.     pwidth = x_visinfo->depth / 8;
  403.     if (pwidth == 3) pwidth = 4;
  404.     mem = ((vid.width*pwidth+3)&~3) * vid.height;
  405.  
  406. //    d_pzbuffer = (unsigned short *) Z_Malloc(vid.width*vid.height*
  407. //        sizeof(*d_pzbuffer));
  408.     d_pzbuffer = (short *) Hunk_HighAllocName(vid.width*vid.height*
  409.         sizeof(*d_pzbuffer), "zbuff");
  410.  
  411.     x_framebuffer[0] = XCreateImage(    x_disp,
  412.         x_vis,
  413.         x_visinfo->depth,
  414.         ZPixmap,
  415.         0,
  416.         Z_Malloc(mem),
  417.         vid.width, vid.height,
  418.         32,
  419.         0);
  420.  
  421.     if (!x_framebuffer[0])
  422.         Sys_Error("VID: XCreateImage failed\n");
  423.  
  424. }
  425.  
  426. void ResetSharedFrameBuffers(void)
  427. {
  428.  
  429.     int size;
  430.     int key;
  431.     int minsize = getpagesize();
  432.     int frm;
  433.  
  434. //    if (d_pzbuffer)
  435. //        Z_Free(d_pzbuffer);
  436.     d_pzbuffer = Hunk_HighAllocName(vid.width*vid.height*sizeof(*d_pzbuffer),"zbuff");
  437.  
  438.     for (frm=0 ; frm<2 ; frm++)
  439.     {
  440.  
  441.     // free up old frame buffer memory
  442.  
  443.         if (x_framebuffer[frm])
  444.         {
  445.             XShmDetach(x_disp, &x_shminfo[frm]);
  446.             free(x_framebuffer[frm]);
  447.             shmdt(x_shminfo[frm].shmaddr);
  448.         }
  449.  
  450.     // create the image
  451.  
  452.         x_framebuffer[frm] = XShmCreateImage(    x_disp,
  453.                         x_vis,
  454.                         x_visinfo->depth,
  455.                         ZPixmap,
  456.                         0,
  457.                         &x_shminfo[frm],
  458.                         vid.width,
  459.                         vid.height );
  460.  
  461.     // grab shared memory
  462.  
  463.         size = x_framebuffer[frm]->bytes_per_line
  464.             * x_framebuffer[frm]->height;
  465.         if (size < minsize)
  466.             Sys_Error("VID: Window must use at least %d bytes\n", minsize);
  467.  
  468.         key = random();
  469.         x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
  470.         if (x_shminfo[frm].shmid==-1)
  471.             Sys_Error("VID: Could not get any shared memory\n");
  472.  
  473.         // attach to the shared memory segment
  474.         x_shminfo[frm].shmaddr =
  475.             (void *) shmat(x_shminfo[frm].shmid, 0, 0);
  476.  
  477.         printf("VID: shared memory id=%d, addr=0x%x\n", x_shminfo[frm].shmid,
  478.             (int) x_shminfo[frm].shmaddr);
  479.  
  480.         x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
  481.  
  482.     // get the X server to attach to it
  483.  
  484.         if (!XShmAttach(x_disp, &x_shminfo[frm]))
  485.             Sys_Error("VID: XShmAttach() failed\n");
  486.         XSync(x_disp, 0);
  487.         shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
  488.  
  489.     }
  490.  
  491. }
  492.  
  493. void VID_MenuDraw( void )
  494. {
  495.     qpic_t        *p;
  496.     char        *ptr;
  497.     int            i, j, column, row, dup;
  498.     char        temp[100];
  499.  
  500.     p = Draw_CachePic ("gfx/vidmodes.lmp");
  501.     M_DrawPic ( (320-p->width)/2, 4, p);
  502.     M_Print (4*8, 36 + MAX_COLUMN_SIZE * 8 + 8, "Video mode switching unavailable");
  503.     M_Print (9*8, 36 + MAX_COLUMN_SIZE * 8 + 8*6, "Press any key...");
  504. }
  505.  
  506. void VID_MenuKey( int key ) { M_Menu_Options_f (); }
  507.  
  508. // Called at startup to set up translation tables, takes 256 8 bit RGB values
  509. // the palette data will go away after the call, so it must be copied off if
  510. // the video driver will need it again
  511.  
  512. byte    surfcache[1024*1024];
  513.  
  514. //
  515. // VID_SetWindowTitle - set the window and icon titles
  516. //
  517.  
  518. void VID_SetWindowTitle( Window win, char *pszName )
  519. {
  520.     XTextProperty    textprop;
  521.     XWMHints        *wmHints;
  522.  
  523.     // Setup ICCCM properties
  524.     textprop.value = (unsigned char *)pszName;
  525.     textprop.encoding = XA_STRING;
  526.     textprop.format = 8;
  527.     textprop.nitems = strlen(pszName);
  528.     wmHints = XAllocWMHints();
  529.     wmHints->initial_state = NormalState;
  530.     wmHints->flags = StateHint;
  531.     XSetWMProperties( x_disp, win, &textprop, &textprop,
  532.                       // Only put WM_COMMAND property on first window.
  533.                       com_argv, com_argc, NULL, NULL, NULL );
  534.     XFree( wmHints );
  535.  
  536.     aWMDelete = XInternAtom( x_disp, "WM_DELETE_WINDOW", False );
  537.     XSetWMProtocols( x_disp, win, &aWMDelete, 1 );
  538. }
  539.  
  540. //
  541. // VID_FullScreen - open the window in full screen mode
  542. //
  543.  
  544. qboolean VID_FullScreen( Window win )
  545. {
  546.     MotifWmHints    hints;
  547.     XWindowChanges  changes;
  548.  
  549.     aHints = XInternAtom( x_disp, "_MOTIF_WM_HINTS", 0 );
  550.     if (aHints == None)
  551.     {
  552.         Con_Printf( "Could not intern X atom for _MOTIF_WM_HINTS." );
  553.         return( false );
  554.     }
  555.  
  556.     hints.flags = MWM_HINTS_DECORATIONS;
  557.     hints.decorations = 0; // Absolutely no decorations.
  558.     XChangeProperty( x_disp, win, aHints, aHints, 32, PropModeReplace, (unsigned char *)&hints, 4 );
  559.  
  560.     changes.x = 0;
  561.     changes.y = 0;
  562.     changes.width = x_screen_width;
  563.     changes.height = x_screen_height;
  564.     changes.stack_mode = TopIf;
  565.     XConfigureWindow( x_disp, win, CWX | CWY | CWWidth | CWHeight | CWStackMode, &changes);
  566.     return( true );
  567. }
  568.  
  569. void    VID_Init (unsigned char *palette)
  570. {
  571.  
  572.     int pnum, i;
  573.     XVisualInfo template;
  574.     int num_visuals;
  575.     int template_mask;
  576.  
  577.     Cmd_AddCommand ("gamma", VID_Gamma_f);
  578.     for (i=0 ; i<256 ; i++)
  579.         vid_gamma[i] = i;
  580.  
  581.     vid.width = 320;
  582.     vid.height = 200;
  583.     vid.aspect = 1.0;
  584.     vid.numpages = 2;
  585.     vid.colormap = host_colormap;
  586.     vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
  587.     //vid.cbits = VID_CBITS;
  588.     //vid.grades = VID_GRADES;
  589.  
  590.     srandom(getpid());
  591.  
  592.     verbose=COM_CheckParm("-verbose");
  593.  
  594. // open the display
  595.     x_disp = XOpenDisplay(0);
  596.     if (!x_disp)
  597.     {
  598.         if (getenv("DISPLAY"))
  599.             Sys_Error("VID: Could not open display [%s]\n",
  600.                 getenv("DISPLAY"));
  601.         else
  602.             Sys_Error("VID: Could not open local display\n");
  603.     }
  604.  
  605.     x_screen = XDefaultScreen( x_disp );
  606.     x_screen_width = WidthOfScreen( ScreenOfDisplay( x_disp, x_screen ) );
  607.     x_screen_height = HeightOfScreen( ScreenOfDisplay( x_disp, x_screen ) );
  608.  
  609.     x_center_width  = x_screen_width/2;
  610.  
  611.     x_center_height = x_screen_height/2;
  612.  
  613.     Con_Printf( "Using screen %d: %dx%d\n", x_screen, x_screen_width, x_screen_height );
  614.  
  615.     x_root_win = XRootWindow( x_disp, x_screen );
  616.  
  617. // catch signals so i can turn on auto-repeat
  618. // we never run full-screen, so no auto-repeat nukage
  619.     if (0)
  620.     {
  621.         struct sigaction sa;
  622.         sigaction(SIGINT, 0, &sa);
  623.         sa.sa_handler = TragicDeath;
  624.         sigaction(SIGINT, &sa, 0);
  625.         sigaction(SIGTERM, &sa, 0);
  626.     }
  627.  
  628.     //XAutoRepeatOff(x_disp);
  629.  
  630. // for debugging only
  631. //    XSynchronize(x_disp, True);
  632.  
  633. // check for command-line window size
  634.     if ((pnum=COM_CheckParm("-winsize")))
  635.     {
  636.         if (pnum >= com_argc-2)
  637.             Sys_Error("VID: -winsize <width> <height>\n");
  638.         vid.width = Q_atoi(com_argv[pnum+1]);
  639.         vid.height = Q_atoi(com_argv[pnum+2]);
  640.         if (!vid.width || !vid.height)
  641.             Sys_Error("VID: Bad window width/height\n");
  642.     }
  643.  
  644.     template_mask = 0;
  645.  
  646. // specify a visual id
  647.     if ((pnum=COM_CheckParm("-visualid")))
  648.     {
  649.         if (pnum >= com_argc-1)
  650.             Sys_Error("VID: -visualid <id#>\n");
  651.         template.visualid = Q_atoi(com_argv[pnum+1]);
  652.         template_mask = VisualIDMask;
  653.     }
  654.  
  655. // If not specified, use default visual
  656.     else
  657.     {
  658.         int screen;
  659.         screen = XDefaultScreen(x_disp);
  660.         template.visualid =
  661.             XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
  662.         template_mask = VisualIDMask;
  663.     }
  664.  
  665. // pick a visual- warn if more than one was available
  666.     x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals);
  667.     if (num_visuals > 1)
  668.     {
  669.         printf("Found more than one visual id at depth %d:\n", template.depth);
  670.         for (i=0 ; i<num_visuals ; i++)
  671.             printf("    -visualid %d\n", (int)(x_visinfo[i].visualid));
  672.     }
  673.     else if (num_visuals == 0)
  674.     {
  675.         if (template_mask == VisualIDMask)
  676.             Sys_Error("VID: Bad visual id %d\n", template.visualid);
  677.         else
  678.             Sys_Error("VID: No visuals at depth %d\n", template.depth);
  679.     }
  680.  
  681.     if (verbose)
  682.     {
  683.         printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
  684.         printf("    class %d\n", x_visinfo->class);
  685.         printf("    screen %d\n", x_visinfo->screen);
  686.         printf("    depth %d\n", x_visinfo->depth);
  687.         printf("    red_mask 0x%x\n", (int)(x_visinfo->red_mask));
  688.         printf("    green_mask 0x%x\n", (int)(x_visinfo->green_mask));
  689.         printf("    blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
  690.         printf("    colormap_size %d\n", x_visinfo->colormap_size);
  691.         printf("    bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
  692.     }
  693.  
  694.     x_vis = x_visinfo->visual;
  695.  
  696. // setup attributes for main window
  697.     {
  698.         int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
  699.         XSetWindowAttributes attribs;
  700.         Colormap tmpcmap;
  701.  
  702.         tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
  703.             x_visinfo->screen), x_vis, AllocNone);
  704.  
  705.         attribs.event_mask = x_std_event_mask;
  706.         attribs.border_pixel = 0;
  707.         attribs.colormap = tmpcmap;
  708.  
  709. // create the main window
  710.         x_win = XCreateWindow(    x_disp,
  711.             XRootWindow(x_disp, x_visinfo->screen),
  712.             0, 0,    // x, y
  713.             vid.width, vid.height,
  714.             0, // borderwidth
  715.             x_visinfo->depth,
  716.             InputOutput,
  717.             x_vis,
  718.             attribmask,
  719.             &attribs );
  720.  
  721.         if (x_visinfo->class != TrueColor)
  722.             XFreeColormap(x_disp, tmpcmap);
  723.  
  724.     }
  725.  
  726.     if (x_visinfo->depth == 8)
  727.     {
  728.  
  729.     // create and upload the palette
  730.         if (x_visinfo->class == PseudoColor)
  731.         {
  732.             x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
  733.             VID_SetPalette(palette);
  734.             XSetWindowColormap(x_disp, x_win, x_cmap);
  735.         }
  736.  
  737.     }
  738.  
  739.     VID_SetWindowTitle( x_win, "Quake" );
  740.  
  741. // create the GC
  742.     {
  743.         XGCValues xgcvalues;
  744.         int valuemask = GCGraphicsExposures;
  745.         xgcvalues.graphics_exposures = False;
  746.         x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
  747.     }
  748.  
  749. // map the window
  750.     XMapWindow(x_disp, x_win);
  751.  
  752. // wait for first exposure event
  753.     {
  754.         XEvent event;
  755.         do
  756.         {
  757.             XNextEvent(x_disp, &event);
  758.             if (event.type == Expose && !event.xexpose.count)
  759.                 oktodraw = true;
  760.         } while (!oktodraw);
  761.     }
  762. // now safe to draw
  763.  
  764. // even if MITSHM is available, make sure it's a local connection
  765.     if (XShmQueryExtension(x_disp))
  766.     {
  767.         char *displayname;
  768.         doShm = true;
  769.         displayname = (char *) getenv("DISPLAY");
  770.         if (displayname)
  771.         {
  772.             char *d = displayname;
  773.             while (*d && (*d != ':')) d++;
  774.             if (*d) *d = 0;
  775.             if (!(!strcasecmp(displayname, "unix") || !*displayname))
  776.                 doShm = false;
  777.         }
  778.     }
  779.  
  780.     if (doShm)
  781.     {
  782.         x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion;
  783.         ResetSharedFrameBuffers();
  784.     }
  785.     else
  786.         ResetFrameBuffer();
  787.  
  788.     current_framebuffer = 0;
  789.     vid.rowbytes = x_framebuffer[0]->bytes_per_line;
  790.     vid.buffer = x_framebuffer[0]->data;
  791.     vid.conbuffer = x_framebuffer[0]->data;
  792.     vid.conrowbytes = vid.rowbytes;
  793.     vid.conwidth = vid.width;
  794.     vid.conheight = vid.height;
  795.  
  796.     vid.maxwarpwidth = WARP_WIDTH;
  797.     vid.maxwarpheight = WARP_HEIGHT;
  798.  
  799.     D_InitCaches (surfcache, sizeof(surfcache));
  800.     
  801. //    XSynchronize(x_disp, False);
  802.  
  803.     vid_menudrawfn = VID_MenuDraw;
  804.     vid_menukeyfn = VID_MenuKey;
  805.  
  806. }
  807.  
  808. void VID_ShiftPalette(unsigned char *p)
  809. {
  810.     VID_SetPalette(p);
  811. }
  812.  
  813. void VID_SetPalette(unsigned char *palette)
  814. {
  815.  
  816.     int i;
  817.     XColor colors[256];
  818.  
  819.     for(i=0;i<256;i++) {
  820.         st2d_8to16table[i]= xlib_rgb16(palette[i*3], palette[i*3+1],palette[i*3+2]);
  821.         st2d_8to24table[i]= xlib_rgb24(palette[i*3], palette[i*3+1],palette[i*3+2]);
  822.     }
  823.  
  824.     if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
  825.     {
  826.         if (palette != current_palette)
  827.             memcpy(current_palette, palette, 768);
  828.         for (i=0 ; i<256 ; i++)
  829.         {
  830.             colors[i].pixel = i;
  831.             colors[i].flags = DoRed|DoGreen|DoBlue;
  832.             colors[i].red = vid_gamma[palette[i*3]] * 257;
  833.             colors[i].green = vid_gamma[palette[i*3+1]] * 257;
  834.             colors[i].blue = vid_gamma[palette[i*3+2]] * 257;
  835.         }
  836.         XStoreColors(x_disp, x_cmap, colors, 256);
  837.     }
  838.  
  839. }
  840.  
  841. // Called at shutdown
  842.  
  843. void    VID_Shutdown (void)
  844. {
  845.     Con_Printf("VID_Shutdown\n");
  846.     //XAutoRepeatOn(x_disp);
  847.     if (mouse_grabbed) {
  848.         /* ungrab the pointer */
  849.         XUngrabPointer(x_disp, CurrentTime);
  850.         XUndefineCursor(x_disp, x_win);
  851.     }
  852.     XCloseDisplay(x_disp);
  853. }
  854.  
  855. int XLateKey(XKeyEvent *ev)
  856. {
  857.  
  858.     int key;
  859.     char buf[64];
  860.     KeySym keysym;
  861.  
  862.     XLookupString(ev, buf, sizeof buf, &keysym, 0);
  863.  
  864.     switch(keysym)
  865.     {
  866.         case XK_Page_Up:     key = K_PGUP; break;
  867.         case XK_Page_Down:     key = K_PGDN; break;
  868.         case XK_Home:     key = K_HOME; break;
  869.         case XK_End:     key = K_END; break;
  870.         case XK_Left:     key = K_LEFTARROW; break;
  871.         case XK_Right:    key = K_RIGHTARROW;        break;
  872.         case XK_Down:     key = K_DOWNARROW; break;
  873.         case XK_Up:         key = K_UPARROW;     break;
  874.         case XK_Escape: key = K_ESCAPE;        break;
  875.         case XK_Return: key = K_ENTER;         break;
  876.         case XK_Tab:        key = K_TAB;             break;
  877.         case XK_F1:         key = K_F1;                break;
  878.         case XK_F2:         key = K_F2;                break;
  879.         case XK_F3:         key = K_F3;                break;
  880.         case XK_F4:         key = K_F4;                break;
  881.         case XK_F5:         key = K_F5;                break;
  882.         case XK_F6:         key = K_F6;                break;
  883.         case XK_F7:         key = K_F7;                break;
  884.         case XK_F8:         key = K_F8;                break;
  885.         case XK_F9:         key = K_F9;                break;
  886.         case XK_F10:        key = K_F10;             break;
  887.         case XK_F11:        key = K_F11;             break;
  888.         case XK_F12:        key = K_F12;             break;
  889.         case XK_BackSpace:
  890.         case XK_Delete: key = K_BACKSPACE; break;
  891.         case XK_Pause:    key = K_PAUSE;         break;
  892.         case XK_Shift_L:
  893.         case XK_Shift_R:        key = K_SHIFT;        break;
  894.         case XK_Control_L: 
  895.         case XK_Control_R:    key = K_CTRL;         break;
  896.         case XK_Alt_L:    
  897.         case XK_Meta_L: 
  898.         case XK_Alt_R:    
  899.         case XK_Meta_R: key = K_ALT;            break;
  900. // various other keys on the keyboard
  901.         case XK_F27: key = K_HOME; break;
  902.         case XK_F29: key = K_PGUP; break;
  903.         case XK_F33: key = K_END; break;
  904.         case XK_F35: key = K_PGDN; break;
  905.         case XK_KP_Insert: key = K_INS; break;
  906.  
  907.         default:
  908.             key = *buf;
  909.             break;
  910.     } 
  911.  
  912.     return key;
  913.  
  914. }
  915.  
  916. struct
  917. {
  918.     int key;
  919.     int down;
  920. } keyq[64];
  921. int keyq_head=0;
  922. int keyq_tail=0;
  923.  
  924. int config_notify=0;
  925. int config_notify_width;
  926. int config_notify_height;
  927.  
  928. void GetEvent(void)
  929. {
  930.     XEvent x_event;
  931.  
  932.     XNextEvent(x_disp, &x_event);
  933.     switch(x_event.type)
  934.     {
  935.         case KeyPress:
  936.             Key_Event(XLateKey(&x_event.xkey), true);
  937.             break;
  938.         case KeyRelease:
  939.             Key_Event(XLateKey(&x_event.xkey), false);
  940.             break;
  941.         case ButtonPress:
  942.             //printf( "button %d down\n", x_event.xbutton.button );
  943.             Key_Event( K_MOUSE1 + x_event.xbutton.button - 1, true );
  944.             break;
  945.         case ButtonRelease:
  946.             //printf( "button %d up\n", x_event.xbutton.button );
  947.             Key_Event( K_MOUSE1 + x_event.xbutton.button - 1, false );
  948.             break;
  949.         case MotionNotify:
  950.             if (mouse_avail && mouse_grabbed) {
  951.                 mouse_x = (float) ((int)x_event.xmotion.x - (int)(vid.width/2));
  952.                 mouse_y = (float) ((int)x_event.xmotion.y - (int)(vid.height/2));
  953.     //printf("m: x=%d,y=%d, mx=%3.2f,my=%3.2f\n", 
  954.     //    x_event.xmotion.x, x_event.xmotion.y, mouse_x, mouse_y);
  955.  
  956.                 /* move the mouse to the window center again */
  957.                 XSelectInput(x_disp,x_win, STD_EVENT_MASK & ~PointerMotionMask);
  958.                 XWarpPointer(x_disp,None,x_win,0,0,0,0, (vid.width/2),(vid.height/2));
  959.                 XSelectInput(x_disp,x_win, STD_EVENT_MASK);
  960.             } else {
  961.                 mouse_x = (float) (x_event.xmotion.x-p_mouse_x);
  962.                 mouse_y = (float) (x_event.xmotion.y-p_mouse_y);
  963.                 p_mouse_x=x_event.xmotion.x;
  964.                 p_mouse_y=x_event.xmotion.y;
  965.             }
  966.             break;
  967.  
  968.         case ConfigureNotify:
  969. //            printf("config notify\n");
  970.             config_notify_width = x_event.xconfigure.width;
  971.             config_notify_height = x_event.xconfigure.height;
  972.             config_notify = 1;
  973.             sb_updates = 0;
  974.             break;
  975.         case Expose:    
  976.             sb_updates = 0;
  977.             break;
  978.         case ClientMessage:
  979.             if (x_event.xclient.data.l[0] == aWMDelete) Host_Quit_f();
  980.             break;
  981.         case EnterNotify:
  982.             mouse_in_window = true;
  983.             break;
  984.         case LeaveNotify:
  985.             mouse_in_window = false;
  986.             break;
  987.  
  988.         default:
  989.             if (doShm && x_event.type == x_shmeventtype)
  990.                 oktodraw = true;
  991.     }
  992.    
  993.     if (mouse_avail) {
  994.         if (key_dest == key_game && !mouse_grabbed && mouse_in_window) {
  995.             mouse_grabbed = true;
  996.             /* grab the pointer */
  997.             XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
  998.                 GrabModeAsync,x_win,None,CurrentTime);
  999.             // inviso cursor
  1000.             XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
  1001.         } else if ((key_dest != key_game || !mouse_in_window) && mouse_grabbed) {
  1002.             mouse_grabbed = false;
  1003.             /* ungrab the pointer */
  1004.             XUngrabPointer(x_disp, CurrentTime);
  1005.             XUndefineCursor(x_disp, x_win);
  1006.         }
  1007.     }
  1008. }
  1009.  
  1010. // flushes the given rectangles from the view buffer to the screen
  1011.  
  1012. void    VID_Update (vrect_t *rects)
  1013. {
  1014. #if 0
  1015.     static int count;
  1016.     static long long s;
  1017.     long long gethrtime();
  1018.  
  1019.     if (count == 0)
  1020.         s = gethrtime();
  1021.  
  1022.     if (count++ == 50) {
  1023.         count = 1;
  1024.         printf("%lf frames/secs\n", 50.0/((double)(gethrtime()-s) / 1e9));
  1025.         s = gethrtime();
  1026.     }
  1027. #endif
  1028.  
  1029. // if the window changes dimension, skip this frame
  1030.  
  1031.     if (config_notify)
  1032.     {
  1033.         printf("config notify\n");
  1034.         config_notify = 0;
  1035.         vid.width = config_notify_width & ~3;
  1036.         vid.height = config_notify_height;
  1037.  
  1038.         printf("w = %d, h = %d\n", vid.width, vid.height);
  1039.  
  1040.         if (doShm)
  1041.             ResetSharedFrameBuffers();
  1042.         else
  1043.             ResetFrameBuffer();
  1044.         vid.rowbytes = x_framebuffer[0]->bytes_per_line;
  1045.         vid.buffer = x_framebuffer[current_framebuffer]->data;
  1046.         vid.conbuffer = vid.buffer;
  1047.         vid.conwidth = vid.width;
  1048.         vid.conheight = vid.height;
  1049.         vid.conrowbytes = vid.rowbytes;
  1050.         vid.recalc_refdef = 1;                // force a surface cache flush
  1051.         return;
  1052.     }
  1053.  
  1054.     if (doShm)
  1055.     {
  1056. //        long long s, gethrtime();
  1057. //        s = gethrtime();
  1058.  
  1059.         while (rects)
  1060.         {
  1061. printf("update: %d,%d (%d,%d)\n", rects->x, rects->y, rects->width, rects->height);
  1062.             if (x_visinfo->depth == 16)
  1063.                 st2_fixup( x_framebuffer[current_framebuffer], 
  1064.                     rects->x, rects->y, rects->width,
  1065.                     rects->height);
  1066.             else if (x_visinfo->depth == 24)
  1067.                 st3_fixup( x_framebuffer[current_framebuffer], 
  1068.                     rects->x, rects->y, rects->width,
  1069.                     rects->height);
  1070.             if (!XShmPutImage(x_disp, x_win, x_gc,
  1071.                 x_framebuffer[current_framebuffer], rects->x, rects->y,
  1072.                 rects->x, rects->y, rects->width, rects->height, True))
  1073.                     Sys_Error("VID_Update: XShmPutImage failed\n");
  1074.             oktodraw = false;
  1075.             while (!oktodraw) GetEvent();
  1076.             rects = rects->pnext;
  1077.         }
  1078. //        printf("%lf\n", (double)(gethrtime()-s)/1.0e9);
  1079.         current_framebuffer = !current_framebuffer;
  1080.         vid.buffer = x_framebuffer[current_framebuffer]->data;
  1081.         vid.conbuffer = vid.buffer;
  1082.         XSync(x_disp, False);
  1083.         
  1084.     }
  1085.     else
  1086.     {
  1087.         while (rects)
  1088.         {
  1089.             if (x_visinfo->depth == 16)
  1090.                 st2_fixup( x_framebuffer[current_framebuffer], 
  1091.                     rects->x, rects->y, rects->width,
  1092.                     rects->height);
  1093.             else if (x_visinfo->depth == 24)
  1094.                 st3_fixup( x_framebuffer[current_framebuffer], 
  1095.                     rects->x, rects->y, rects->width,
  1096.                     rects->height);
  1097.             XPutImage(x_disp, x_win, x_gc, x_framebuffer[0], rects->x,
  1098.                 rects->y, rects->x, rects->y, rects->width, rects->height);
  1099.             rects = rects->pnext;
  1100.         }
  1101.         XSync(x_disp, False);
  1102.     }
  1103. }
  1104.  
  1105. static int dither;
  1106.  
  1107. void VID_DitherOn(void)
  1108. {
  1109.     if (dither == 0)
  1110.     {
  1111.         vid.recalc_refdef = 1;
  1112.         dither = 1;
  1113.     }
  1114. }
  1115.  
  1116. void VID_DitherOff(void)
  1117. {
  1118.     if (dither)
  1119.     {
  1120.         vid.recalc_refdef = 1;
  1121.         dither = 0;
  1122.     }
  1123. }
  1124.  
  1125. void VID_SetDefaultMode( void )
  1126. {
  1127. }
  1128.  
  1129. int I_OpenWindow(void)
  1130. {
  1131.     return 0;
  1132. }
  1133.  
  1134. void I_EraseWindow(int window)
  1135. {
  1136. }
  1137.  
  1138. void I_DrawCircle(int window, int x, int y, int r)
  1139. {
  1140. }
  1141.  
  1142. void I_DisplayWindow(int window)
  1143. {
  1144. }
  1145.  
  1146. void Sys_SendKeyEvents(void)
  1147. {
  1148. // get events from x server
  1149.     if (x_disp)
  1150.     {
  1151.         while (XPending(x_disp)) GetEvent();
  1152.         while (keyq_head != keyq_tail)
  1153.         {
  1154.             Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down);
  1155.             keyq_tail = (keyq_tail + 1) & 63;
  1156.         }
  1157.     }
  1158. }
  1159.  
  1160. #if 0
  1161. char *Sys_ConsoleInput (void)
  1162. {
  1163.  
  1164.     static char    text[256];
  1165.     int        len;
  1166.     fd_set  readfds;
  1167.     int        ready;
  1168.     struct timeval timeout;
  1169.  
  1170.     timeout.tv_sec = 0;
  1171.     timeout.tv_usec = 0;
  1172.     FD_ZERO(&readfds);
  1173.     FD_SET(0, &readfds);
  1174.     ready = select(1, &readfds, 0, 0, &timeout);
  1175.  
  1176.     if (ready>0)
  1177.     {
  1178.         len = read (0, text, sizeof(text));
  1179.         if (len >= 1)
  1180.         {
  1181.             text[len-1] = 0;    // rip off the /n and terminate
  1182.             return text;
  1183.         }
  1184.     }
  1185.  
  1186.     return 0;
  1187.     
  1188. }
  1189. #endif
  1190.  
  1191. void IN_Init (void)
  1192. {
  1193.     Cvar_RegisterVariable (&m_filter);
  1194.     if ( COM_CheckParm ("-nomouse") )
  1195.         return;
  1196.     mouse_x = mouse_y = 0.0;
  1197.     mouse_avail = 1;
  1198. }
  1199.  
  1200. void IN_Shutdown (void)
  1201. {
  1202.     mouse_avail = 0;
  1203. }
  1204.  
  1205. void IN_Commands (void)
  1206. {
  1207.     int i;
  1208.    
  1209.     if (!mouse_avail) return;
  1210.    
  1211.     for (i=0 ; i<mouse_buttons ; i++) {
  1212.         if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
  1213.             Key_Event (K_MOUSE1 + i, true);
  1214.  
  1215.         if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
  1216.             Key_Event (K_MOUSE1 + i, false);
  1217.     }
  1218.     mouse_oldbuttonstate = mouse_buttonstate;
  1219. }
  1220.  
  1221. void IN_Move (usercmd_t *cmd)
  1222. {
  1223.     if (!mouse_avail)
  1224.         return;
  1225.    
  1226.     if (m_filter.value) {
  1227.         mouse_x = (mouse_x + old_mouse_x) * 0.5;
  1228.         mouse_y = (mouse_y + old_mouse_y) * 0.5;
  1229.     }
  1230.  
  1231.     old_mouse_x = mouse_x;
  1232.     old_mouse_y = mouse_y;
  1233.    
  1234.     mouse_x *= sensitivity.value;
  1235.     mouse_y *= sensitivity.value;
  1236.    
  1237.     if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
  1238.         cmd->sidemove += m_side.value * mouse_x;
  1239.     else
  1240.         cl.viewangles[YAW] -= m_yaw.value * mouse_x;
  1241.     if (in_mlook.state & 1)
  1242.         V_StopPitchDrift ();
  1243.    
  1244.     if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) {
  1245.         cl.viewangles[PITCH] += m_pitch.value * mouse_y;
  1246.         if (cl.viewangles[PITCH] > 80)
  1247.             cl.viewangles[PITCH] = 80;
  1248.         if (cl.viewangles[PITCH] < -70)
  1249.             cl.viewangles[PITCH] = -70;
  1250.     } else {
  1251.         if ((in_strafe.state & 1) && noclip_anglehack)
  1252.             cmd->upmove -= m_forward.value * mouse_y;
  1253.         else
  1254.             cmd->forwardmove -= m_forward.value * mouse_y;
  1255.     }
  1256.     mouse_x = mouse_y = 0.0;
  1257. }
  1258.